<html>
    <head>
        <meta charset="utf-8"/>
        <script src="wasm_exec.js"></script>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/go/go.min.js"></script>
        <style>
            .CodeMirror {
                height: 400px;
                border: 1px solid #ccc;
                font-size: 14px;
            }
            body {
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                max-width: 1200px;
                margin: 0 auto;
                padding: 20px;
                background-color: #f5f5f5;
            }
            .container {
                background: white;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            }
            button {
                background: #007acc;
                color: white;
                border: none;
                padding: 10px 20px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 16px;
                margin: 10px 0;
            }
            button:hover {
                background: #005a9e;
            }
            #output {
                background: #f8f8f8;
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 15px;
                margin-top: 20px;
                white-space: pre-wrap;
                font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
                font-size: 13px;
                min-height: 100px;
            }
        </style>
        <script>
            let go = new Go();
            let editor;
            const examples = {
                Example1: `package main\n\nimport \"fmt\"\n\nfunc MaybeInt() int? { Some(42) }\n\nfunc main() {\n    fmt.Println(MaybeInt())\n\n    arr := []int{1, 2, 3}\n    sum := arr.Map({ $0 + 1 }).Sum()\n    fmt.Println(\"Sum:\", sum) // 9\n}`,
                sumArray: `package main\n\nimport \"fmt\"\n\nfunc main() {\n    arr := []int{1, 2, 3, 4, 5}\n    fmt.Println(\"Sum:\", arr.Sum())\n}`,
                stringBuiltIns: `package main

import "fmt"

func main() {
    fmt.Println("Hello World!".Lowercased())
    fmt.Println("Hello World!".Uppercased())
    fmt.Println("Hello World!".Contains("World"))
    fmt.Println("Hello World!".HasPrefix("Hello"))
    fmt.Println("Hello World!".HasSuffix("World!"))
    fmt.Println("Hello World!".TrimPrefix("Hello "))
    fmt.Println("Hello World!".ReplaceAll("!", "!!!"))
    fmt.Println("42".U64()?)
    fmt.Println("0b101010".Int()?)
}
`,
                vecBuiltIns: `package main\n\nimport \"fmt\"\n\nfunc main() {\n    fmt.Printf("Min: %v\\n", []int{1, 2, 3}.Min())\n    fmt.Printf("Max: %v\\n", []int{1, 2, 3}.Max())\n    fmt.Printf("Find(2): %v\\n", []int{1, 2, 3}.Find({ $0 == 2 }))\n    fmt.Printf("Find(42): %v\\n", []int{1, 2, 3}.Find({ $0 == 42 }))\n    fmt.Printf("Reversed: %v\\n", []int{1, 2, 3}.Reversed())\n}`,
                enum1: `package main

import "fmt"

type IpAddr enum {
    V4(u8, u8, u8, u8)
    V6(string)
}

func isPrivate(ip IpAddr) bool {
    match ip {
    case IpAddr.V4(a, b, _, _):
        return (a == 10) || (a == 172 && b >= 16 && b <= 31) || (a == 192 && b == 168)
    case IpAddr.V6(s):
        return s.HasPrefix("fc00::")
    }
    return true
}

type Coin enum {
    Penny
    Nickel
    Dime
    Quarter
}

func valueInCents(coin Coin) int {
    switch coin {
    case Coin.Penny:   return 1
    case Coin.Nickel:  return 5
    case Coin.Dime:    return 10
    case Coin.Quarter: return 25
    default:           return 0
    }
}

func main() {
    home := IpAddr.V4(127, 0, 0, 1)
    loopback := IpAddr.V6("::1")
    fmt.Println("home ip is private:", home, isPrivate(home))
    fmt.Println("loopback:", loopback)

    cents := valueInCents(Coin.Nickel)
    fmt.Println("cents:", cents)
}
`,
                set1: `package main

func main() {
    s1 := set[int]{1, 2, 3}
    s2 := set[int]{1, 2, 3, 4, 5}
    printf("s1.IsSubset(s2):                   %v", s1.IsSubset(s2))
    printf("s2.IsSuperset(s1):                 %v", s2.IsSuperset(s1))
    printf("s1.Union(s2):                      %v", s1.Union(s2))
    printf("s1.Contains(2):                    %v", s1.Contains(2))
    printf("s1.ContainsWhere({ $0 %% 2 == 0 }): %v", s1.ContainsWhere({ $0 % 2 == 0 }))
    printf("s2.Filter({ $0 %% 2 != 0 }):        %v", s2.Filter({ $0 % 2 != 0 }))
    printf("s1.Min():                          %v", s1.Min())
    printf("s1.Max():                          %v", s1.Max())
    printf("s1.Intersection(s2):               %v", s1.Intersection(s2))
    printf("s1.Intersects(s2):                 %v", s1.Intersects(s2))
    printf("s1.IsDisjoint(s2):                 %v", s1.IsDisjoint(s2))
    printf("s2.Subtracting(s1):                %v", s2.Subtracting(s1))
    printf("s1.SymmetricDifference(s2):        %v", s1.SymmetricDifference(s2))
    printf("s1.Len():                          %v", s1.Len())
    printf("s1.IsEmpty():                      %v", s1.IsEmpty())
}
`,
            };

            async function runWasmWithInput(inputText) {
                // Set up args: first is program name, then your args
                go.argv = ["main.wasm", "execute", inputText];

                // Capture output
                const outputElem = document.getElementById("output");
                let output = "";
                const origLog = console.log;
                const origErr = console.error;
                console.log = function(...args) {
                    output += args.join(" ") + "\n";
                    origLog.apply(console, args);
                };
                console.error = function(...args) {
                    output += args.join(" ") + "\n";
                    origErr.apply(console, args);
                };

                outputElem.textContent = ""; // Clear previous output

                try {
                    const result = await WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject);
                    await go.run(result.instance);
                } finally {
                    console.log = origLog;
                    console.error = origErr;
                    outputElem.textContent = output;
                }
            }

            async function runInPlayground() {
                const code = editor.getValue();
                const outputElem = document.getElementById("output");
                
                // First, get the generated Go code
                go.argv = ["main.wasm", "execute", code];
                
                let generatedCode = "";
                const origLog = console.log;
                const origErr = console.error;
                console.log = function(...args) {
                    generatedCode += args.join(" ") + "\n";
                    origLog.apply(console, args);
                };
                console.error = function(...args) {
                    generatedCode += args.join(" ") + "\n";
                    origErr.apply(console, args);
                };

                try {
                    const result = await WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject);
                    await go.run(result.instance);
                } finally {
                    console.log = origLog;
                    console.error = origErr;
                }

                // Check for EXIT_CODE:1 and display as error if present
                if (generatedCode.includes("EXIT_CODE:1")) {
                    const cleanedOutput = generatedCode.replace(/EXIT_CODE:1\s*/g, "");
                    outputElem.textContent = "Error:\n" + cleanedOutput;
                    return;
                }

                // Now send to Go Playground
                outputElem.textContent = "Sending to Go Playground...";
                
                try {
                    const response = await fetch("https://play.golang.org/compile", {
                        method: "POST",
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded",
                        },
                        body: `body=${encodeURIComponent(generatedCode)}`
                    });
                    
                    const data = await response.json();
                    
                    if (data.Errors) {
                        outputElem.textContent = `Compilation Error:\n${data.Errors}`;
                    } else if (data.Events && data.Events.length > 0) {
                        const allMessages = data.Events
                            .filter(event => event.Message)
                            .map(event => event.Message)
                            .join('');
                        outputElem.textContent = `Execution Output:\n${allMessages}`;
                    } else {
                        outputElem.textContent = "No output";
                    }
                } catch (error) {
                    outputElem.textContent = `Error sending to Go Playground: ${error.message}`;
                }
            }

            window.onload = function() {
                // Initialize CodeMirror
                editor = CodeMirror(document.getElementById("code"), {
                    value: examples["Example1"],
                    mode: "go",
                    theme: "monokai",
                    lineNumbers: true,
                    autoCloseBrackets: true,
                    matchBrackets: true,
                    indentUnit: 4,
                    tabSize: 4,
                    indentWithTabs: false,
                    lineWrapping: true,
                    extraKeys: {
                        "Ctrl-Space": "autocomplete"
                    }
                });
                document.getElementById("exampleSelect").onchange = function() {
                    const selected = this.value;
                    if (examples[selected]) {
                        editor.setValue(examples[selected]);
                    }
                };
                document.getElementById("playgroundBtn").onclick = function() {
                    runInPlayground();
                };
            };
        </script>
    </head>
    <body>
        <div class="container">
            <h1>AGL Playground</h1>
            <label for="exampleSelect">Examples:</label>
            <select id="exampleSelect">
                <option value="Example1">Example1</option>
                <option value="sumArray">Sum array</option>
                <option value="stringBuiltIns">String build-ins</option>
                <option value="vecBuiltIns">Vec build-ins</option>
                <option value="enum1">Enum</option>
                <option value="set1">Set</option>
            </select>
            <div id="code"></div>
            <button id="playgroundBtn">Run</button>
            <pre id="output"></pre>
        </div>
    </body>
</html>
